#include "Editor.h"
#include "EditorGUI.h"
#include "CGUIEmptyElement.h"
#include "IEditorTool.h"
#include <AntTweakBar.h>
#include <string>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH
#include <mapformat.pb.h>

using namespace irr;
using namespace video;
using namespace gui;
using namespace core;

struct
{
	int Position;
	int Rotation;
	int Scale;
	int Visible;
}VarType={0,1,2,3};

EditorGUI::EditorGUI(Editor* editor)
:IEditorComponent(editor),env(0),currentTool(0),gui(0),entityData(new mapformat::Entity),saveData(entityData)
{
}

EditorGUI::~EditorGUI()
{
	delete entityData;
	gui->drop();
	TwTerminate();
}

void EditorGUI::init()
{
	irr::IrrlichtDevice* device=editor->game->getIrrlichtDevice();
	env=device->getGUIEnvironment();
	//toolbar
	gui=new CGUIEmptyElement(env,0);
	toolbar=env->addToolBar(gui);	
	addTool(new QuitTool(editor));
	//treeview
	treeView=env->addTreeView(core::recti(10,400,100,600),gui,-1,true,true);
	editor->bindGUIEvent(treeView,boost::bind(&EditorGUI::treeViewCallback,this,_1));
	//AntTweakBar
	switch(device->getVideoDriver()->getDriverType())
	{
	case EDT_DIRECT3D9:
		TwInit(TW_DIRECT3D9,device->getVideoDriver()->getExposedVideoData().D3D9.D3DDev9);
	break;
	case EDT_OPENGL:
		TwInit(TW_OPENGL,0);
	break;
	}
	rect<s32> vp=device->getVideoDriver()->getViewPort();
	TwWindowSize(vp.getWidth(),vp.getHeight());

	//Basic properties
	TwBar* bar=TwNewBar("Basic");
	TwDefine("Basic label='Basic properties' position='10 39' size='200 240' movable=false");
	TwStructMember vectorStructMember[] = {
    { "x", TW_TYPE_FLOAT, offsetof(vector3df, X), ""},
    { "y", TW_TYPE_FLOAT, offsetof(vector3df, Y), ""},
    { "z", TW_TYPE_FLOAT, offsetof(vector3df, Z), ""}
	};
	const char* step="step=0.02";
	TwStructMember vectorStructMember2[] = {
    { "x", TW_TYPE_FLOAT, offsetof(vector3df, X), step},
    { "y", TW_TYPE_FLOAT, offsetof(vector3df, Y), step},
    { "z", TW_TYPE_FLOAT, offsetof(vector3df, Z), step}
	};
	TwType vectortype=TwDefineStruct("Vector",vectorStructMember,3,sizeof(vector3df),NULL,NULL);
	TwType vectortype2=TwDefineStruct("Vector2",vectorStructMember2,3,sizeof(vector3df),NULL,NULL);
	
	TwAddVarCB(bar,"Position",vectortype,setVarCallback,getVarCallback,&VarType.Position,NULL);
	TwAddVarCB(bar,"Rotation",vectortype,setVarCallback,getVarCallback,&VarType.Rotation,NULL);
	TwAddVarCB(bar,"Scale",vectortype2,setVarCallback,getVarCallback,&VarType.Scale,NULL);
	TwAddVarCB(bar,"Visible",TW_TYPE_BOOLCPP,setVarCallback,getVarCallback,&VarType.Visible,"true='Yes' false='No'");
	//Entity creation
	editor->factory->getProductList(productList);
	TwBar* createBar=TwNewBar("EntityCreation");	
	foreach(std::string& product,productList)
	{
		TwAddButton(createBar,product.c_str(),createButtonCallback,const_cast<char*>(product.c_str()),"");
	}
	TwDefine("EntityCreation label='Entity Creation' position='512 39' size='170 240'");
	//Property
	propertyBar=TwNewBar("Property");

	editor->newEntitySelected.connect(boost::bind(&EditorGUI::newEntitySelected,this,_1));
}

void EditorGUI::addTool(IEditorTool* tool)
{
	IGUIButton* button=toolbar->addButton(tools.size(),0,tool->getToolTipText().c_str(),editor->game->getIrrlichtDevice()->getVideoDriver()->getTexture(tool->getIcon()),0,
		tool->isPushButton(),true);
	editor->bindGUIEvent(button,bind(&IEditorTool::OnEvent,tool,_1));
	tools.push_back(tool);
}

void EditorGUI::render()
{
	env->drawAll();
	TwDraw();
}

void EditorGUI::onPreEdit()
{
	env->getRootGUIElement()->addChild(gui);
	env->getRootGUIElement()->bringToFront(gui);
	env->setFocus(gui);
	
	treeView->getRoot()->clearChilds();
	editor->currentMap->iterateEntites(this);
}

void EditorGUI::onPostEdit()
{
	env->getRootGUIElement()->removeChild(gui);
}

void EditorGUI::addEntity(SGF::IEntity* entity)
{
	core::stringw className=editor->factory->getProductName(entity);
	gui::IGUITreeViewNode* node=treeView->getRoot()->addChildBack(className.c_str());
	node->setData(entity);
}

void EditorGUI::treeViewCallback(const irr::SEvent& ev)
{
	switch(ev.GUIEvent.EventType)
	{
	case irr::gui::EGET_TREEVIEW_NODE_SELECT:
	{
		gui::IGUITreeViewNode* node=treeView->getLastEventNode();
		SGF::IEntity* entity=(SGF::IEntity*)(node->getData());
		if(entity)
			editor->selectEntity(entity);
	}
	break;
	}
}

bool EditorGUI::iterate(SGF::IEntity* entity)
{
	addEntity(entity);
	return true;
}

void EditorGUI::newEntitySelected(SGF::IEntity* entity)
{
	TwRemoveAllVars(propertyBar);
	if(entity)
	{
		saveData.dataMap.clear();
		entityData->Clear();
		entity->onSave(saveData);
		for(std::map<std::string,SaveValue>::iterator i=saveData.dataMap.begin();i!=saveData.dataMap.end();++i)
		{
			SaveValue value=i->second;
			switch(value.type)
			{
			case SaveValue::Int:
				TwAddVarCB(propertyBar,i->first.c_str(),TW_TYPE_INT32,setPropertyCallback,getPropertyCallback,
			break;
			}
		}
	}
}

void TW_CALL EditorGUI::setVarCallback(const void *value, void *clientData)
{
	IEntity* entity=Editor::getInstance()->getSelectedEntity();
	if(!entity)
		return;
	switch(*(int*)clientData)
	{
	case 0:
		entity->setPosition(*(vector3df*)(value));
	break;
	case 1:
		entity->setRotation(*(vector3df*)(value));
	break;
	case 2:
		entity->setScale(*(vector3df*)(value));
	break;
	case 3:
		entity->setVisible(*(bool*)(value));
	break;
	}
}

void TW_CALL EditorGUI::getVarCallback(void *value, void *clientData)
{
	IEntity* entity=Editor::getInstance()->getSelectedEntity();
	if(!entity)
		return;
	switch(*(int*)clientData)
	{
	case 0:
		*(vector3df*)value=entity->getPosition();
	break;
	case 1:
		*(vector3df*)value=entity->getRotation();
	break;
	case 2:
		*(vector3df*)value=entity->getScale();
	break;
	case 3:
		*(bool*)value=entity->isVisible();
	break;
	}
}

void TW_CALL EditorGUI::createButtonCallback(void* data)
{
	const char* productName=(const char*)data;
	SGF::MapState* map=Editor::getInstance()->currentMap;
	if(map)
	{
		SGF::IEntity* entity=(SGF::IEntity*)(Editor::getInstance()->factory->create(productName));
		if(entity)
		{
			entity->init(map);
			map->addEntity(entity);
			irr::scene::ISceneManager* smgr=Editor::getInstance()->game->getIrrlichtDevice()->getSceneManager();
			irr::scene::ICameraSceneNode* camera=smgr->getActiveCamera();
			Ogre::Vector3 newPosition;
			camera->getAbsoluteTransformation().transformVect(newPosition,Ogre::Vector3(0.f,0.f,20.0f));
			entity->setPosition(newPosition);
			((EditorGUI*)(Editor::getInstance()->gui))->addEntity(entity);
		}
	}
}